// 验证给定的字符串是否可以解释为十进制数字。

// 例如:

// "0" => true
// " 0.1 " => true
// "abc" => false
// "1 a" => false
// "2e10" => true
// " -90e3   " => true
// " 1e" => false
// "e3" => false
// " 6e-1" => true
// " 99e2.5 " => false
// "53.5e93" => true
// " --6 " => false
// "-+3" => false
// "95a54e53" => false

// 说明: 我们有意将问题陈述地比较模糊。在实现代码之前，你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表：

// 数字 0-9
// 指数 - "e"
// 正/负号 - "+"/"-"
// 小数点 - "."
// 当然，在输入中，这些字符的上下文也很重要。

#include <string>
#include <vector>

using namespace std;

/*
有限自动状态机
0初始无输入或者只有space的状态
1输入了数字之后的状态
2前面无数字，只输入了Dot的状态
3输入了符号状态
4前面有数字和有dot的状态
5'e' or 'E'输入后的状态
6输入e之后输入Sign的状态
7输入e后输入数字的状态
8前面有有效数输入之后，输入space的状态

输入可以分：
INVALID, // 0 Include: Alphas, '(', '&' ans so on
SPACE, // 1
SIGN, // 2 '+','-'
DIGIT, // 3 numbers
DOT, // 4 '.'
EXPONENT, // 5 'e' 'E'
*/

class Solution {
public:
    bool isNumber(string s) {
        enum class InputType {
            INVALID = 0,    // 0 Include: Alphas, '(', '&' ans so on
            SPACE = 1,      // 1
            SIGN = 2,       // 2 '+', '-'
            DIGIT = 3,      // 3 numbers
            DOT = 4,        // 4 '.'
            EXPONENT = 5,   // 5 'e', 'E'
        };
        vector<vector<int>> transTable(9, vector<int>(6));
        transTable = {
            {-1, 0, 3, 1, 2, -1},    // 0 初始无输入或者只有space的状态
            {-1, 8, -1, 1, 4, 5},    // 1 输入了数字之后的状态
			{-1, -1, -1, 4, -1, -1}, // 2 前面无数字，只输入了Dot的状态
			{-1, -1, -1, 1, 2, -1},  // 3 输入了符号状态
			{-1, 8, -1, 4, -1, 5},   // 4 前面有数字和有dot的状态
			{-1, -1, 6, 7, -1, -1},  // 5 'e' or 'E'输入后的状态
			{-1, -1, -1, 7, -1, -1}, // 6 输入e之后输入Sign的状态
			{-1, 8, -1, 7, -1, -1},  // 7 输入e后输入数字的状态
			{-1, 8, -1, -1, -1, -1}, // 8 前面有有效数输入之后，输入space的状态
        };
        int state{0};
        int n = s.size();
        int i{0};
        while (i != n) {
            InputType input = InputType::INVALID;
            if (s[i] == ' ') input = InputType::SPACE;
            else if (s[i] == '+' || s[i] == '-') input = InputType::SIGN;
            else if (isdigit(s[i])) input = InputType::DIGIT;
            else if (s[i] == '.') input = InputType::DOT;
            else if (s[i] == 'e' || s[i] == 'E') input = InputType:: EXPONENT;
            state = transTable[state][static_cast<int>(input)];
            if (state == -1) return false;
            ++i;
        }
        return state == 1 || state == 4 || state == 7 || state == 8;
    }
};

#include "../stdc++.h"

class Solution {
public:
    enum State {
        STATE_INITIAL,
        STATE_INT_SIGN,
        STATE_INTEGER,
        STATE_POINT,
        STATE_POINT_WITHOUT_INT,
        STATE_FRACTION,
        STATE_EXP,
        STATE_EXP_SIGN,
        STATE_EXP_NUMBER,
        STATE_END
    };

    enum CharType {
        CHAR_NUMBER,
        CHAR_EXP,
        CHAR_POINT,
        CHAR_SIGN,
        CHAR_ILLEGAL
    };

    CharType toCharType(char ch) {
        if (ch >= '0' && ch <= '9') {
            return CHAR_NUMBER;
        } else if (ch == 'e' || ch == 'E') {
            return CHAR_EXP;
        } else if (ch == '.') {
            return CHAR_POINT;
        } else if (ch == '+' || ch == '-') {
            return CHAR_SIGN;
        } else {
            return CHAR_ILLEGAL;
        }
    }

    bool isNumber(string s) {
        unordered_map<State, unordered_map<CharType, State>> transfer{
            {
                STATE_INITIAL, {
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_POINT, STATE_POINT_WITHOUT_INT},
                    {CHAR_SIGN, STATE_INT_SIGN}
                }
            }, {
                STATE_INT_SIGN, {
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_POINT, STATE_POINT_WITHOUT_INT}
                }
            }, {
                STATE_INTEGER, {
                    {CHAR_NUMBER, STATE_INTEGER},
                    {CHAR_EXP, STATE_EXP},
                    {CHAR_POINT, STATE_POINT}
                }
            }, {
                STATE_POINT, {
                    {CHAR_NUMBER, STATE_FRACTION},
                    {CHAR_EXP, STATE_EXP}
                }
            }, {
                STATE_POINT_WITHOUT_INT, {
                    {CHAR_NUMBER, STATE_FRACTION}
                }
            }, {
                STATE_FRACTION,
                {
                    {CHAR_NUMBER, STATE_FRACTION},
                    {CHAR_EXP, STATE_EXP}
                }
            }, {
                STATE_EXP,
                {
                    {CHAR_NUMBER, STATE_EXP_NUMBER},
                    {CHAR_SIGN, STATE_EXP_SIGN}
                }
            }, {
                STATE_EXP_SIGN, {
                    {CHAR_NUMBER, STATE_EXP_NUMBER}
                }
            }, {
                STATE_EXP_NUMBER, {
                    {CHAR_NUMBER, STATE_EXP_NUMBER}
                }
            }
        };

        int len = s.length();
        State st = STATE_INITIAL;

        for (int i = 0; i < len; i++) {
            CharType typ = toCharType(s[i]);
            if (transfer[st].find(typ) == transfer[st].end()) {
                return false;
            } else {
                st = transfer[st][typ];
            }
        }
        return st == STATE_INTEGER || st == STATE_POINT || st == STATE_FRACTION || st == STATE_EXP_NUMBER || st == STATE_END;
    }
};
